home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / Reference / DevCon / Milan_1991 / Devcon91.4 / AppShell / Examples / MultiProj / project.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-01  |  25.7 KB  |  986 lines

  1. /*************************************************************************
  2.   *                                                                      *
  3.   *                            Preliminary                               *
  4.   *                        Amiga AppShell (tm)                           *
  5.   *                                                                      *
  6.   *  Copyright (c) 1990,1991 Commodore-Amiga, Inc. All Rights Reserved.  *
  7.   *                                                                      *
  8.   *   This software and information is proprietary, preliminary, and     *
  9.   *   subject to change without notice.                                  *
  10.   *                                                                      *
  11.   *                            DISCLAIMER                                *
  12.   *                                                                      *
  13.   *   THIS SOFTWARE IS PROVIDED "AS IS".                                 *
  14.   *   NO REPRESENTATIONS OR WARRANTIES ARE MADE WITH RESPECT TO THE      *
  15.   *   ACCURACY, RELIABILITY, PERFORMANCE, CURRENTNESS, OR OPERATION      *
  16.   *   OF THIS SOFTWARE, AND ALL USE IS AT YOUR OWN RISK.                 *
  17.   *   NEITHER COMMODORE NOR THE AUTHORS ASSUME ANY RESPONSIBILITY OR     *
  18.   *   LIABILITY WHATSOEVER WITH RESPECT TO YOUR USE OF THIS SOFTWARE.    *
  19.   *                                                                      *
  20.   *                          Non-Disclosure                              *
  21.   *                                                                      *
  22.   *   This information is not to be disclosed to any other company,      *
  23.   *   individual or party.  Discussion is to be restricted to CBM        *
  24.   *   approved discussion areas, such as the closed conferences on bix;  *
  25.   *   amiga.cert, amiga.com, amiga.beta/appshell.                        *
  26.   *                                                                      *
  27.   ************************************************************************
  28.   */
  29.  
  30. #include "multiproj.h"
  31.  
  32. #define    DI(x)    ;
  33.  
  34. void kprintf (void *, ...);
  35.  
  36. /* Project function table */
  37. struct Funcs PTable[] =
  38. {
  39.  /* Function with an argument template */
  40.     {"New",  PNewFunc,  NewID,},
  41.     {"Open", POpenFunc, OpenID, "FILENAME,FORCE/S", 2L, },
  42.     {"Save", PSaveFunc, SaveID, ",", 0L, },
  43.     {"SaveAs",PSaveAsFunc, SaveAsID, "NAME", 1L, },
  44.     {"About",PAboutFunc, AboutID, },
  45.     {"Quit", PQuitFunc, QuitID, "FORCE/S,ALL/S", 2L, },
  46.     {"Change", ChangeFunc, ChangeID, },
  47.  
  48.  /* These function can not be accessed by the user */
  49.     {"PInit", PInitFunc, PInitID, NULL, NULL, APSHF_PRIVATE},
  50.     {"OpenMain", OpenMainFunc, OpenMainID, NULL, NULL, APSHF_PRIVATE},
  51.     {"OpenAbout", OpenAboutFunc, OpenAboutID, NULL, NULL, APSHF_PRIVATE},
  52.     {"DropIcon",  DropIconFunc,  DropIconID, NULL, NULL, APSHF_PRIVATE,},
  53.     {"PExit", PExitFunc, PExitID, NULL, NULL, APSHF_PRIVATE},
  54.  
  55.  /* Marks the end of the array */
  56.     {NULL, NO_FUNCTION,}
  57. };
  58.  
  59. /* All text used in the application must be defined in a text array.  Then
  60.  * referred to by numeric ID. */
  61. STRPTR Def_Text[] =
  62. {
  63.  /* Padding */
  64.     "",
  65.     "Loading...",
  66.  
  67.  /* Main window menus */
  68.     " TITLE PROJECT  LABEL Project",
  69.     "  ITEM NEW      LABEL New                  KEY N CMD New",
  70.     "  ITEM OPEN     LABEL \"Open...\"          KEY O CMD Open",
  71.     "   BAR",
  72.     "  ITEM SAVE     LABEL Save                 KEY S CMD Save",
  73.     "  ITEM SAVEAS   LABEL \"Save As...\"       KEY A CMD SaveAs",
  74.     "   BAR",
  75.     "  ITEM CLOSE    LABEL Close                      CMD Quit",
  76.     "   BAR",
  77.     "  ITEM ABOUT    LABEL \"About...\"               CMD About",
  78.     "   BAR",
  79.     "  ITEM QUIT     LABEL \"Quit MultiProj\"   KEY Q CMD \"Quit All\"",
  80.  
  81.     " TITLE EXTRAS   LABEL Extras",
  82.     "  ITEM CHANGE   LABEL \"Change Project\"   KEY / CMD Change",
  83.     "  ITEM CMDSHELL LABEL \"Command Shell...\" KEY . CMD CmdShell",
  84.     "   END",
  85.  
  86.     "Aborted by user",
  87. #define    PERR_USER_ABORT    18
  88.  
  89.     "No name provided",
  90. #define    PERR_NO_NAME    19
  91.  
  92.     "Couldn't load %s",
  93. #define    PERR_CANT_LOAD    20
  94.  
  95.     "Requires project",
  96. #define    PERR_NO_PROJECT    21
  97.  
  98.     "Couldn't create %s",
  99. #define    PERR_CANT_CREATE 22
  100.  
  101.     "Couldn't write to %s",
  102. #define    PERR_CANT_WRITE    23
  103.  
  104.  /* NULL termination is required */
  105.     NULL
  106. };
  107.  
  108. /* The following tag array consists of GadTool tags for Window Environment
  109.  * objects. */
  110. struct TagItem td_tags[] =
  111. {
  112.     {APSH_GTFlags, PLACETEXT_IN},
  113.     {TAG_DONE,},
  114. };
  115.  
  116. /* These are the objects that are going to be within our main window.
  117.  * Note that the window itself is an object, and receives the SAME name
  118.  * as in the WindowEnvironment tag list, APSH_NameTag.  If you want
  119.  * to specify any window tags, attach them to the window object. */
  120. struct Object objects[] =
  121. {
  122.     {&objects[1], 0, 0, OBJ_Window, NULL, NULL, NULL, "Main", 1L,
  123.      {0, 0, 320, 0}, },
  124.  
  125.     {NULL,        0, 0, OBJ_Text,   NULL, NULL, NULL, "Name", 0L,
  126.      {8, 4, 350, 10}, td_tags, },
  127. };
  128.  
  129. /* This is a Window Environment tag list.  It describes a window. */
  130. struct TagItem mainenv[] =
  131. {
  132.     {APSH_NameTag, (ULONG) "Main"},
  133.     {APSH_Objects, (ULONG) objects},
  134.     {APSH_TTMenu, 2L},
  135.     {APSH_WinAOpen, OpenMainID},
  136.     {APSH_RefreshData, OpenMainID},
  137.     {TAG_DONE,}
  138. };
  139.  
  140.  /* Command Shell user interface environment specification array */
  141. struct TagItem Handle_DOS[] =
  142. {
  143.  /* Presence of this tag, makes the Command Shell to stay closed until
  144.   * the user sends a CMDSHELL OPEN command. */
  145.     {APSH_Status, APSHP_INACTIVE},
  146.     {APSH_Rating, APSH_REQUIRED},
  147.     {TAG_DONE,}
  148. };
  149.  
  150. /* These tags describe the Intuition user interface. */
  151. struct TagItem Handle_IDCMP[] =
  152. {
  153.     {APSH_Rating, APSH_REQUIRED},
  154.     {TAG_DONE,}
  155. };
  156.  
  157.  /* ARexx user interface environment specification array */
  158. static struct TagItem Handle_AREXX[] =
  159. {
  160.     {APSH_Extens, (ULONG) "skel"},
  161.     {APSH_Rating, APSH_OPTIONAL},
  162.     {TAG_DONE,}
  163. };
  164.  
  165. /* These tags describe the Simple IPC user interface. */
  166. static struct TagItem Handle_SIPC[] =
  167. {
  168.     {APSH_Rating, APSH_REQUIRED},
  169.     {TAG_DONE,}
  170. };
  171.  
  172. struct TagItem appwinenv[] =
  173. {
  174.     {APSH_NameTag, (ULONG) "MAIN"},    /* Window to make into AppWindow */
  175.     {APSH_AppDDrop, DropIconID},    /* function after drop */
  176.     {APSH_CmdFlags, APSH_WBF_NOLIST},    /* Don't add the icons to any list */
  177.     {TAG_DONE,}
  178. };
  179.  
  180. /* These tags describe the Workbench user interface. */
  181. struct TagItem Handle_WB[] =
  182. {
  183.     {APSH_AppWindowEnv, (ULONG) appwinenv},
  184.     {APSH_Rating, APSH_OPTIONAL},
  185.     {TAG_DONE,}
  186. };
  187.  
  188. /* Application Environment:
  189.  * Tell about our slave project application */
  190. struct TagItem Project_App[] =
  191. {
  192.  /* About the application */
  193.     {APSH_AppName, (ULONG) APPNAME},
  194.     {APSH_AppVersion, (ULONG) APPVERS},
  195.     {APSH_AppCopyright, (ULONG) APPCOPY},
  196.     {APSH_AppAuthor, (ULONG) APPAUTH},
  197.  
  198.  /* Specify the application function table */
  199.     {APSH_FuncTable, (ULONG) PTable},
  200.  
  201.  /* Specify the application text table */
  202.     {APSH_DefText, (ULONG) Def_Text},
  203.  
  204.  /* Tell how memory we need for our own data */
  205.     {APSH_UserDataSize, sizeof (struct AppData)},
  206.  
  207.  /* Must always specify the SIPC user interface */
  208.     {APSH_AddSIPC_UI, (ULONG) Handle_SIPC},
  209.  
  210.  /* Add an ARexx user interface */
  211.     {APSH_AddARexx_UI, (ULONG) Handle_AREXX},
  212.  
  213.  /* Add a Command Shell user interface */
  214.     {APSH_AddCmdShell_UI, (ULONG) Handle_DOS},
  215.  
  216.  /* Add an Intuition user interface */
  217.     {APSH_AddIntui_UI, (ULONG) Handle_IDCMP},
  218.  
  219.  /* Add a Workbench user interface */
  220.     {APSH_AddWB_UI, (ULONG) Handle_WB},
  221.  
  222.  /* Specify a custom initialization routine */
  223.     {APSH_AppInit, PInitID},
  224.     {APSH_AppExit, PExitID},
  225.  
  226.     {TAG_DONE,}
  227. };
  228.  
  229. /* local functions */
  230. LONG save_project (struct AppInfo *ai, STRPTR name);
  231. LONG load_project (struct AppInfo *ai, STRPTR name);
  232. SHORT myEasyRequest (struct Window *, UBYTE *, ULONG *, UBYTE *, UBYTE *, int, ...);
  233. BOOL CheckForChanges (struct AppInfo * ai, struct ProjNode * pn);
  234. LONG FixFileAndPath (struct FileRequester *rf, STRPTR name);
  235.  
  236.  /* Sample initialization function */
  237. VOID PInitFunc (struct Hook *h, struct AppInfo *ai, struct AppFunction *af)
  238. {
  239.     struct AppData *ad = (struct AppData *) ai->ai_UserData;
  240.     struct Project *p = &(ai->ai_Project);
  241.     struct TagItem *attrs = af->af_Attrs;
  242.     extern struct TagItem mainenv[];
  243.     struct ProjNode *pn;
  244.     WORD i;
  245.  
  246.     /* Get a pointer to our project node */
  247.     DI (kprintf ("PInitFunc enter\n"));
  248.     if (pn = (struct ProjNode *) GetTagData (APSH_ProjInfo, NULL, attrs))
  249.     {
  250.     /* Remember the project node */
  251.     p->p_CurProj = ad->ad_PN = pn;
  252.  
  253.     /* Get a pointer to our Master's AppInfo */
  254.     ad->ad_MAI = (struct AppInfo *) GetTagData (APSH_AppHandle, NULL, attrs);
  255.  
  256.     /* Allocate the file requesters */
  257.     for (i = 0; i < FR_MAX; i++)
  258.     {
  259.         ad->ad_FR[i] = AllocAslRequest (ASL_FileRequest, NULL);
  260.     }
  261.  
  262.     /* Unset the file requester positioning */
  263.     ad->ad_Width = (-1);
  264.  
  265.     /* Initialize the file requester */
  266.     FixFileAndPath (ad->ad_FR[FR_PROJ], pn->pn_ProjPath);
  267.  
  268.     /* Open the Main window */
  269.     DI (kprintf ("Open Main window\n"));
  270.     HandlerFunc (ai,
  271.              APSH_Handler, "IDCMP",
  272.              APSH_Command, APSH_MH_OPEN,
  273.              APSH_WindowEnv, (ULONG) mainenv,
  274.              TAG_DONE);
  275.     }
  276.     else
  277.     {
  278.     /* We require a project node */
  279.     ai->ai_Pri_Ret = RETURN_ERROR;
  280.     ai->ai_Sec_Ret = PERR_NO_PROJECT;
  281.     ai->ai_TextRtn =
  282.       PrepText (ai, APSH_USER_ID, ai->ai_Sec_Ret, NULL);
  283.     }
  284.     DI (kprintf ("PInitFunc exit\n"));
  285. }
  286.  
  287. /* This function gets called after the main event processing loop exits,
  288.  * and before deallocating all the user interfaces.  It is specified by the
  289.  * APSH_AppExit tag in the Application Description tag array.  Note that the
  290.  * AppData structure which has been allocated for us, is deallocated by
  291.  * AppShell after freeing the user interfaces. */
  292.  
  293. VOID
  294. PExitFunc (struct Hook *h, struct AppInfo *ai, struct AppFunction *af)
  295. {
  296.     struct AppData *ad = (struct AppData *) ai->ai_UserData;
  297.     WORD i;
  298.  
  299.     if (ad)
  300.     {
  301.     /* Free the file requesters */
  302.     for (i = 0; i < FR_MAX; i++)
  303.     {
  304.         /* Do we have a file requester? */
  305.         if (ad->ad_FR[i])
  306.         {
  307.         /* Free the file requester */
  308.         FreeFileRequest (ad->ad_FR[i]);
  309.         ad->ad_FR[i] = NULL;
  310.         }
  311.     }
  312.     }
  313. }
  314.  
  315. /* This function is called every time the Main window is opened.  It
  316.  * was specified by using the APSH_WinAOpen tag in the Main Window
  317.  * Environemt tag array.  I'm also 'cheating' and calling it everytime
  318.  * I want to refresh the window and graphics. */
  319.  
  320. VOID OpenMainFunc (struct Hook *h, struct AppInfo *ai, struct AppFunction *af)
  321. {
  322.     struct AppData *ad = (struct AppData *) ai->ai_UserData;
  323.     struct Window *win;
  324.     struct Gadget *gad;
  325.  
  326.     /* Update the mode gadget */
  327.     if (APSHGetGadgetInfo (ai, "Main", "Name", (ULONG *) & win, (ULONG *) & gad))
  328.     {
  329.     /* Update the string gadget */
  330.     GT_SetGadgetAttrs (gad, win, NULL,
  331.                GTTX_Text, ad->ad_PN->pn_ProjPath,
  332.                TAG_DONE);
  333.     }
  334.  
  335.     /* Set the window title */
  336.     sprintf (ad->ad_Tmp, "window title \"%s\"", ad->ad_PN->pn_Name);
  337.     PerfFunc (ai, NULL, ad->ad_Tmp, NULL);
  338. }
  339.  
  340.  /* Create a new project work area */
  341. VOID PNewFunc (struct Hook *h, struct AppInfo *ai, struct AppFunction *af)
  342. {
  343.     struct AppData *ad = (struct AppData *) ai->ai_UserData;
  344.     struct MsgHandler *mh;
  345.  
  346.     /* Make sure we have a master */
  347.     if (ad->ad_MAI)
  348.     {
  349.     /* See if they have a SIPC port */
  350.     if (mh = HandlerData (ad->ad_MAI, APSH_Handler, "SIPC", TAG_DONE))
  351.     {
  352.         /* Tell our master to open a new application */
  353.         HandlerFunc (ai,
  354.              APSH_Handler, "SIPC",
  355.              APSH_Command, AH_SENDCMD,
  356.              APSH_NameTag, mh->mh_PortName,
  357.              APSH_CmdString, (ULONG) "New",
  358.              TAG_DONE);
  359.     }
  360.     }
  361. }
  362.  
  363.  /* Open a project into the existing work area */
  364. VOID POpenFunc (struct Hook *h, struct AppInfo *ai, struct AppFunction *af)
  365. {
  366.     struct AppData *ad = (struct AppData *) ai->ai_UserData;
  367.     struct FileRequester *fr = ad->ad_FR[FR_PROJ];
  368.     struct TagItem *attrs = af->af_Attrs;
  369.     struct Funcs *f;
  370.     STRPTR name = NULL;
  371.     BOOL cancel = FALSE;
  372.     BOOL force = FALSE;
  373.  
  374.     /* set the wait pointer */
  375.     APSHSetWaitPointer (ai, NULL);
  376.  
  377.     /* See if we have a parsed command */
  378.     if (f = af->af_FE)
  379.     {
  380.     /* See if they passed a file name */
  381.     name = (STRPTR) f->fe_Options[0];
  382.  
  383.     /* Did they set the force switch? */
  384.     force = (BOOL) f->fe_Options[1];
  385.     }
  386.     else
  387.     {
  388.     /* See if they passed a name with a tag */
  389.     name = (STRPTR) GetTagData (APSH_NameTag, NULL, attrs);
  390.     }
  391.  
  392.     /* Is there an existing project? */
  393.     if (!force)
  394.     {
  395.     BOOL cancel = FALSE;
  396.  
  397.     /* Prompt user */
  398.     if (cancel = CheckForChanges (ai, ad->ad_PN))
  399.     {
  400.         return;
  401.     }
  402.     }
  403.  
  404.     /* Do we need to prompt for a name? */
  405.     if (!(name))
  406.     {
  407.     /* Do we have a file requester? */
  408.     if (fr)
  409.     {
  410.         struct TagItem tg[10];
  411.         struct Window *win = NULL;
  412.  
  413.         /* Get the window pointer */
  414.         APSHGetWindowInfo (ai, "Main", (ULONG *) & win);
  415.  
  416.         /* Initialize the file requester position */
  417.         if (ad->ad_Width == (-1))
  418.         {
  419.         ad->ad_LeftEdge = (win) ? (win->BorderLeft + 1) : 0;
  420.         ad->ad_TopEdge = (win) ? win->BorderTop : 0;
  421.         ad->ad_Width = 320;
  422.         ad->ad_Height = MAX (((win) ? (win->Height - (win->BorderTop + win->BorderBottom)) : 150), 140);
  423.         }
  424.  
  425.         /* Set the file requester position */
  426.         tg[4].ti_Tag = ASL_LeftEdge;
  427.         tg[4].ti_Data = (ULONG) (win) ? (win->LeftEdge + ad->ad_LeftEdge) : ad->ad_LeftEdge;
  428.         tg[5].ti_Tag = ASL_TopEdge;
  429.         tg[5].ti_Data = (ULONG) (win) ? (win->TopEdge + ad->ad_TopEdge) : ad->ad_TopEdge;
  430.         tg[6].ti_Tag = ASL_Width;
  431.         tg[6].ti_Data = (ULONG) ad->ad_Width;
  432.         tg[7].ti_Tag = ASL_Height;
  433.         tg[7].ti_Data = (ULONG) ad->ad_Height;
  434.  
  435.         tg[0].ti_Tag = ASL_Hail;
  436.         tg[0].ti_Data = (ULONG) "Select File to Open";
  437.         tg[1].ti_Tag = ASL_FuncFlags;
  438.         tg[1].ti_Data = NULL;
  439.         tg[2].ti_Tag = ASL_OKText;
  440.         tg[2].ti_Data = (ULONG) "Open";
  441.         tg[3].ti_Tag = ASL_Window;
  442.         tg[3].ti_Data = (ULONG) win;
  443.         tg[8].ti_Tag = ASL_Pattern;
  444.         tg[8].ti_Data = (ULONG) "~(#?.info)";
  445.         tg[9].ti_Tag = TAG_DONE;
  446.  
  447.         /* Request the name */
  448.         if (AslRequest (fr, tg))
  449.         {
  450.         /* Fix the entries */
  451.         FixFileAndPath (fr, NULL);
  452.         strcpy (ad->ad_Name, fr->rf_Dir);
  453.         AddPart (ad->ad_Name, fr->rf_File, 510);
  454.  
  455.         /* See if a name was entered */
  456.         if (FixFileAndPath (fr, ad->ad_Name))
  457.         {
  458.             name = ad->ad_Name;
  459.         }
  460.         }
  461.         else
  462.         {
  463.         /* User aborted requester */
  464.         ai->ai_Pri_Ret = RETURN_WARN;
  465.         ai->ai_Sec_Ret = PERR_USER_ABORT;
  466.         ai->ai_TextRtn =
  467.           PrepText (ai, APSH_USER_ID, PERR_USER_ABORT, NULL);
  468.  
  469.         /* Canceled */
  470.         cancel = TRUE;
  471.         }
  472.  
  473.         /* Remember where they moved it */
  474.         ad->ad_LeftEdge = fr->rf_LeftEdge - ((win) ? win->LeftEdge : 0);
  475.         ad->ad_TopEdge = fr->rf_TopEdge - ((win) ? win->TopEdge : 0);
  476.         ad->ad_Width = fr->rf_Width;
  477.         ad->ad_Height = fr->rf_Height;
  478.     }
  479.     }
  480.  
  481.     /* Do we have a file name */
  482.     if (!cancel && name)
  483.     {
  484.     /* LOAD THE PROJECT HERE */
  485.     if (load_project (ai, name))
  486.     {
  487.         UBYTE node[128];
  488.         BPTR lock;
  489.  
  490.         /* Parse the name */
  491.         stcgfp (ad->ad_Tmp, name);
  492.         stcgfn (node, name);
  493.  
  494.         /* Get a lock on the directory */
  495.         if (lock = Lock (ad->ad_Tmp, ACCESS_READ))
  496.         {
  497.         struct WBArg wbarg;
  498.  
  499.         /* Fill in the WBArg */
  500.         wbarg.wa_Lock = lock;
  501.         wbarg.wa_Name = node;
  502.  
  503.         /* Update the project node */
  504.         UpdateProject (ai, ad->ad_PN, &wbarg);
  505.  
  506.         /* Unlock our temporary lock */
  507.         UnLock (lock);
  508.         }
  509.  
  510.         /* Clear the change flag */
  511.         ad->ad_PN->pn_Changed = FALSE;
  512.  
  513.         /* Refresh the display */
  514.         OpenMainFunc (h, ai, af);
  515.     }
  516.     }
  517.     else if (!cancel)
  518.     {
  519.     /* No name given */
  520.     ai->ai_Pri_Ret = RETURN_ERROR;
  521.     ai->ai_Sec_Ret = PERR_NO_NAME;
  522.     ai->ai_TextRtn =
  523.       PrepText (ai, APSH_USER_ID, PERR_NO_NAME, NULL);
  524.     }
  525.  
  526.     /* clear the wait pointer */
  527.     APSHClearPointer (ai, NULL);
  528. }
  529.  
  530. /* This gets called when a Workbench icon is dropped on the main window. */
  531. VOID DropIconFunc (struct Hook *h, struct AppInfo *ai, struct AppFunction *af)
  532. {
  533.     struct AppData *ad = (struct AppData *) ai->ai_UserData;
  534.     struct TagItem *attrs = af->af_Attrs;
  535.     struct WBArg *wbarg;
  536.     BOOL cancel = FALSE;
  537.  
  538.     /* Has there been changes? */
  539.     if (cancel = CheckForChanges (ai, ad->ad_PN))
  540.     {
  541.     return;
  542.     }
  543.  
  544.     if (wbarg = (struct WBArg *) GetTagData (APSH_WBArg, NULL, attrs))
  545.     {
  546.     BPTR lock;
  547.  
  548.     /* Go to the directory represented by the icon */
  549.     if (lock = CurrentDir (wbarg->wa_Lock))
  550.     {
  551.         /* Get the name of the directory */
  552.         NameFromLock (wbarg->wa_Lock, ad->ad_Name, 510);
  553.         AddPart (ad->ad_Name, wbarg->wa_Name, 510);
  554.  
  555.         /* LOAD THE PROJECT HERE */
  556.         if (load_project (ai, ad->ad_Name))
  557.         {
  558.         /* Update the project node */
  559.         UpdateProject (ai, ad->ad_PN, wbarg);
  560.  
  561.         /* Clear the change flag */
  562.         ad->ad_PN->pn_Changed = FALSE;
  563.  
  564.         /* Refresh the display */
  565.         OpenMainFunc (h, ai, af);
  566.         }
  567.  
  568.         /* Go back home */
  569.         CurrentDir (lock);
  570.     }
  571.     }
  572. }
  573.  
  574.  /* Save the current project */
  575. VOID PSaveFunc (struct Hook *h, struct AppInfo *ai, struct AppFunction *af)
  576. {
  577.     struct AppData *ad = (struct AppData *) ai->ai_UserData;
  578.  
  579.     /* Not named yet */
  580.     if ((ad->ad_PN->pn_ProjName == NULL) ||
  581.     (strlen (ad->ad_PN->pn_ProjName) == 0L))
  582.     {
  583.     PSaveAsFunc (h, ai, af);
  584.     }
  585.     /* Is there an existing project? */
  586.     else
  587.     {
  588.     /* Save the file */
  589.     if (save_project (ai, ad->ad_PN->pn_ProjPath))
  590.     {
  591.         /* Clear the change flag */
  592.         ad->ad_PN->pn_Changed = FALSE;
  593.     }
  594.     }
  595. }
  596.  
  597.  /* Save the current project */
  598. VOID PSaveAsFunc (struct Hook *h, struct AppInfo *ai, struct AppFunction *af)
  599. {
  600.     struct AppData *ad = (struct AppData *) ai->ai_UserData;
  601.     struct FileRequester *fr = ad->ad_FR[FR_PROJ];
  602.     struct TagItem *attrs = af->af_Attrs;
  603.     struct Funcs *f;
  604.     STRPTR name = NULL;
  605.     BOOL cancel = FALSE;
  606.  
  607.     /* set the wait pointer */
  608.     APSHSetWaitPointer (ai, NULL);
  609.  
  610.     /* See if we have a parsed command */
  611.     if (f = af->af_FE)
  612.     {
  613.     /* See if they passed a file name */
  614.     name = (STRPTR) f->fe_Options[0];
  615.     }
  616.     else
  617.     {
  618.     /* See if they passed a name with a tag */
  619.     name = (STRPTR) GetTagData (APSH_NameTag, NULL, attrs);
  620.     }
  621.  
  622.     /* Do we need to prompt for a name? */
  623.     if (!(name))
  624.     {
  625.     /* Do we have a file requester? */
  626.     if (fr)
  627.     {
  628.         struct TagItem tg[10];
  629.         struct Window *win = NULL;
  630.  
  631.         /* Get the window pointer */
  632.         APSHGetWindowInfo (ai, "Main", (ULONG *) & win);
  633.  
  634.         /* Initialize the file requester position */
  635.         if (ad->ad_Width == (-1))
  636.         {
  637.         ad->ad_LeftEdge = (win) ? (win->BorderLeft + 1) : 0;
  638.         ad->ad_TopEdge = (win) ? win->BorderTop : 0;
  639.         ad->ad_Width = 320;
  640.         ad->ad_Height = MAX (((win) ? (win->Height - (win->BorderTop + win->BorderBottom)) : 150), 160);
  641.         }
  642.  
  643.         /* Set the file requester position */
  644.         tg[4].ti_Tag = ASL_LeftEdge;
  645.         tg[4].ti_Data = (ULONG) (win) ? (win->LeftEdge + ad->ad_LeftEdge) : ad->ad_LeftEdge;
  646.         tg[5].ti_Tag = ASL_TopEdge;
  647.         tg[5].ti_Data = (ULONG) (win) ? (win->TopEdge + ad->ad_TopEdge) : ad->ad_TopEdge;
  648.         tg[6].ti_Tag = ASL_Width;
  649.         tg[6].ti_Data = (ULONG) ad->ad_Width;
  650.         tg[7].ti_Tag = ASL_Height;
  651.         tg[7].ti_Data = (ULONG) ad->ad_Height;
  652.  
  653.         tg[0].ti_Tag = ASL_Hail;
  654.         tg[0].ti_Data = (ULONG) "Select File to Save";
  655.         tg[1].ti_Tag = ASL_FuncFlags;
  656.         tg[1].ti_Data = (FILF_SAVE | FILF_PATGAD);
  657.         tg[2].ti_Tag = ASL_OKText;
  658.         tg[2].ti_Data = (ULONG) "Save";
  659.         tg[3].ti_Tag = ASL_Window;
  660.         tg[3].ti_Data = (ULONG) win;
  661.         tg[8].ti_Tag = ASL_Pattern;
  662.         tg[8].ti_Data = (ULONG) "~(#?.info)";
  663.         tg[9].ti_Tag = TAG_DONE;
  664.  
  665.         /* Request the name */
  666.         if (AslRequest (fr, tg))
  667.         {
  668.         /* Fix the entries */
  669.         FixFileAndPath (fr, NULL);
  670.         strcpy (ad->ad_Name, fr->rf_Dir);
  671.         AddPart (ad->ad_Name, fr->rf_File, 510);
  672.  
  673.         /* See if a name was entered */
  674.         if (FixFileAndPath (fr, ad->ad_Name))
  675.         {
  676.             name = ad->ad_Name;
  677.         }
  678.         }
  679.         else
  680.         {
  681.         /* User aborted requester */
  682.         ai->ai_Pri_Ret = RETURN_WARN;
  683.         ai->ai_Sec_Ret = PERR_USER_ABORT;
  684.         ai->ai_TextRtn =
  685.           PrepText (ai, APSH_USER_ID, ai->ai_Sec_Ret, NULL);
  686.  
  687.         /* Canceled */
  688.         cancel = TRUE;
  689.         }
  690.  
  691.         /* Remember where they moved it */
  692.         ad->ad_LeftEdge = fr->rf_LeftEdge - ((win) ? win->LeftEdge : 0);
  693.         ad->ad_TopEdge = fr->rf_TopEdge - ((win) ? win->TopEdge : 0);
  694.         ad->ad_Width = fr->rf_Width;
  695.         ad->ad_Height = fr->rf_Height;
  696.     }
  697.     }
  698.  
  699.     /* Do we have a file name */
  700.     if (!cancel && name)
  701.     {
  702.     /* Save the file */
  703.     if (save_project (ai, name))
  704.     {
  705.         UBYTE node[128];
  706.         BPTR lock;
  707.  
  708.         /* Parse the name */
  709.         stcgfp (ad->ad_Tmp, name);
  710.         stcgfn (node, name);
  711.  
  712.         /* Get a lock on the directory */
  713.         if (lock = Lock (ad->ad_Tmp, ACCESS_READ))
  714.         {
  715.         struct WBArg wbarg;
  716.  
  717.         /* Fill in the WBArg */
  718.         wbarg.wa_Lock = lock;
  719.         wbarg.wa_Name = node;
  720.  
  721.         /* Update the project node */
  722.         UpdateProject (ai, ad->ad_PN, &wbarg);
  723.  
  724.         /* Unlock our temporary lock */
  725.         UnLock (lock);
  726.         }
  727.  
  728.         /* Set the real file name */
  729.         FixFileAndPath (fr, ad->ad_PN->pn_ProjPath);
  730.  
  731.         /* Clear the change flag */
  732.         ad->ad_PN->pn_Changed = FALSE;
  733.     }
  734.  
  735.     /* Refresh the display */
  736.     OpenMainFunc (h, ai, af);
  737.     }
  738.     else if (!cancel)
  739.     {
  740.     /* No name given */
  741.     ai->ai_Pri_Ret = RETURN_ERROR;
  742.     ai->ai_Sec_Ret = PERR_NO_NAME;
  743.  
  744.     ai->ai_TextRtn =
  745.       PrepText (ai, APSH_USER_ID, ai->ai_Sec_Ret, NULL);
  746.     }
  747.  
  748.     /* clear the wait pointer */
  749.     APSHClearPointer (ai, NULL);
  750. }
  751.  
  752.  /* Shutdown routine */
  753. VOID PQuitFunc (struct Hook *h, struct AppInfo *ai, struct AppFunction *af)
  754. {
  755.     struct AppData *ad = (struct AppData *) ai->ai_UserData;
  756.     struct MsgHandler *mh;
  757.     ULONG FuncID = CloseID;
  758.     BOOL cancel = FALSE;
  759.     BOOL force = FALSE;
  760.     BOOL all = FALSE;
  761.     struct Funcs *f;
  762.  
  763.     /* set the wait pointer */
  764.     APSHSetWaitPointer (ai, NULL);
  765.  
  766.     /* See if we have a parsed command */
  767.     if (f = af->af_FE)
  768.     {
  769.     /* Did they set the force switch? */
  770.     force = (BOOL) f->fe_Options[0];
  771.  
  772.     /* Close all windows? */
  773.     if (all = (BOOL) f->fe_Options[1])
  774.     {
  775.         FuncID = QuitID;
  776.     }
  777.     }
  778.  
  779.     /* Is there an existing project? */
  780.     if (!force)
  781.     {
  782.     /* Prompt user */
  783.     if (cancel = CheckForChanges (ai, ad->ad_PN))
  784.     {
  785.         return;
  786.     }
  787.     }
  788.  
  789.     /* Make sure we have a master */
  790.     if (ad->ad_MAI)
  791.     {
  792.     /* Get a handle on our master's SIPC port */
  793.     if (mh = HandlerData (ad->ad_MAI, APSH_Handler, "SIPC", TAG_DONE))
  794.     {
  795.         /* Prepare our Tags */
  796.         ad->ad_TL[0].ti_Tag = APSH_ProjInfo;
  797.         ad->ad_TL[0].ti_Data = (ULONG) ad->ad_PN;
  798.         ad->ad_TL[1].ti_Tag = TAG_DONE;
  799.  
  800.         /* Tell our master to close this project work area */
  801.         HandlerFunc (ai,
  802.              APSH_Handler, "SIPC",
  803.              APSH_Command, AH_SENDCMD,
  804.              APSH_NameTag, (ULONG) mh->mh_PortName,
  805.              APSH_CmdID,   FuncID,
  806.              APSH_CmdData, (ULONG) ad->ad_TL,
  807.              TAG_DONE);
  808.     }
  809.     }
  810.  
  811.     /* Tell the AppShell that we're all done now. */
  812.     ai->ai_Done = TRUE;
  813.  
  814.     /* set the wait pointer */
  815.     APSHClearPointer (ai, NULL);
  816. }
  817.  
  818.  /* Simulate a changed project */
  819. VOID ChangeFunc (struct Hook *h, struct AppInfo *ai, struct AppFunction *af)
  820. {
  821.     struct AppData *ad = (struct AppData *) ai->ai_UserData;
  822.  
  823.     /* Indicate a change */
  824.     ad->ad_PN->pn_Changed = TRUE;
  825. }
  826.  
  827. #define    REALLY_SAVE    FALSE
  828.  
  829. LONG save_project (struct AppInfo *ai, STRPTR name)
  830. {
  831.     LONG retval = FALSE;
  832.  
  833. #if REALLY_SAVE
  834.     BPTR fh;
  835.  
  836.     /* Create a new file */
  837.     if (fh = Open (name, MODE_NEWFILE))
  838.     {
  839.     /* Write something to the file here */
  840.     if (Write (fh, name, strlen (name)) >= 0)
  841.     {
  842.         /* Show that we couldn't write to the project */
  843.         ai->ai_Pri_Ret = RETURN_FAIL;
  844.         ai->ai_Sec_Ret = PERR_CANT_WRITE;
  845.         ai->ai_TextRtn =
  846.         PrepText (ai, APSH_USER_ID, ai->ai_Sec_Ret, (int)name);
  847.     }
  848.  
  849.     /* Close the file */
  850.     Close (fh);
  851.  
  852. #else
  853.  
  854.     /* Make sure they gave us a name */
  855.     if (1)
  856.     {
  857.  
  858. #endif
  859.     /* Indicate that we were able to save the project */
  860.     retval = TRUE;
  861.     }
  862.     else
  863.     {
  864.     /* Show that we couldn't create the project */
  865.     ai->ai_Pri_Ret = RETURN_FAIL;
  866.     ai->ai_Sec_Ret = PERR_CANT_CREATE;
  867.     ai->ai_TextRtn =
  868.         PrepText (ai, APSH_USER_ID, ai->ai_Sec_Ret, (int)name);
  869.     }
  870.  
  871.     return (retval);
  872. }
  873.  
  874. LONG load_project (struct AppInfo *ai, STRPTR name)
  875. {
  876.     struct AppData *ad = (struct AppData *) ai->ai_UserData;
  877.     struct FileRequester *fr = ad->ad_FR[FR_PROJ];
  878.     LONG retval = FALSE;
  879.     BPTR fh;
  880.  
  881.     /* Open an existing file */
  882.     if (fh = Open (name, MODE_OLDFILE))
  883.     {
  884.     /* Close the file */
  885.     Close (fh);
  886.  
  887.     /* Set the real file name */
  888.     FixFileAndPath (fr, name);
  889.  
  890.     /* Indicate that we were able to open the project */
  891.     retval = TRUE;
  892.     }
  893.     else
  894.     {
  895.     /* Show that we couldn't load the project */
  896.     ai->ai_Pri_Ret = RETURN_FAIL;
  897.     ai->ai_Sec_Ret = PERR_CANT_LOAD;
  898.     ai->ai_TextRtn =
  899.         PrepText (ai, APSH_USER_ID, ai->ai_Sec_Ret, (int)name);
  900.     }
  901.  
  902.     return (retval);
  903. }
  904.  
  905. /* Error handling routine */
  906. SHORT myEasyRequest (struct Window *win, UBYTE *title, ULONG *idcmp,
  907.              UBYTE *fpat, UBYTE *fbuts, int arg1, ...)
  908. {
  909.     struct EasyStruct myEs = {NULL};
  910.  
  911.     myEs.es_StructSize = sizeof (struct EasyStruct);
  912.     myEs.es_Title = title;
  913.     myEs.es_TextFormat = fpat;
  914.     myEs.es_GadgetFormat = fbuts;
  915.     return ((SHORT) (EasyRequestArgs (win, &myEs, idcmp, &arg1)));
  916. }
  917.  
  918. BOOL CheckForChanges (struct AppInfo * ai, struct ProjNode * pn)
  919. {
  920.     BOOL cancel = FALSE;
  921.  
  922.     if (pn->pn_Changed)
  923.     {
  924.     UBYTE pname[255];
  925.     SHORT button;
  926.  
  927.     strcpy (pname, pn->pn_Name);
  928.  
  929.     if (strlen (pname) < 1)
  930.     {
  931.         strcpy (pname, "<UnNamed>");
  932.     }
  933.  
  934.     /* Project has been changed, do you want to save first? */
  935.     button = myEasyRequest (ai->ai_Window, ai->ai_AppName, NULL,
  936.         "%s\nhas been changed.", "Continue|Save First|Cancel",
  937.         (int)pname);
  938.  
  939.     switch (button)
  940.     {
  941.         case 1:        /* Nope, don't save */
  942.         break;
  943.  
  944.         case 2:        /* Yes, please save */
  945.         PSaveFunc (NULL, ai, NULL);
  946.         break;
  947.  
  948.         case 0:        /* Woops! Cancel */
  949.         /* clear the wait pointer */
  950.         APSHClearPointer (ai, NULL);
  951.  
  952.         cancel = TRUE;
  953.         break;
  954.     }
  955.     }
  956.  
  957.     return (cancel);
  958. }
  959.  
  960. /* Get the file requester set up properly.  Returns 0 if no file node
  961.  * present, returns > 0 if there is a file node.  */
  962. LONG FixFileAndPath (struct FileRequester *rf, STRPTR name)
  963. {
  964.     LONG count = 0L;
  965.  
  966.     if (rf)
  967.     {
  968.     if (name)
  969.     {
  970.         stcgfp (rf->rf_Dir, name);
  971.         count = (LONG) stcgfn (rf->rf_File, name);
  972.     }
  973.     else
  974.     {
  975.         WORD dlen = (strlen (rf->rf_Dir) - 1);
  976.  
  977.         if ((dlen > 0) && (rf->rf_Dir[dlen] == '/'))
  978.         {
  979.         rf->rf_Dir[dlen] = 0;
  980.         }
  981.     }
  982.     }
  983.  
  984.     return (count);
  985. }
  986.